
// ===============================================================================================================
// -*- C++ -*-
//
// Matrix4x4.hpp - OpenGL compatible utility class for a 4x4 matrix of floats.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __MATRIX4X4_HPP__
#define __MATRIX4X4_HPP__

#include <Math.hpp>
#include <Vector.hpp>

///
/// Homogeneous 4x4 column-major matrix, for affine 3D transformations.
/// Rotations are counterclockwise. Uses a right-handed coordinate system.
/// \note Optmized with SSE intrinsics.
///
SSE_ALIGN(class) Matrix4x4 {

public:

	#if (ENABLE_SSE_INTRINSICS)
	union {
		struct {
			__m128 col[4]; ///< 4 cols of the matrix
		};
		float m[16]; ///< Matrix elements (column major - OpenGL style)
	};
	#else
	float m[16];
	#endif // ENABLE_SSE_INTRINSICS

	/* Layout:
	| m[0] m[4] m[8]  m[12] |
	| m[1] m[5] m[9]  m[13] |
	| m[2] m[6] m[10] m[14] |
	| m[3] m[7] m[11] m[15] | */

public:

	// Constructors:

	explicit Matrix4x4(bool identity = false);

	Matrix4x4(const Matrix4x4 & mat);
	Matrix4x4& operator = (const Matrix4x4 & mat);

	Matrix4x4(float m0, float m4, float  m8, float m12,
			  float m1, float m5, float  m9, float m13,
			  float m2, float m6, float m10, float m14,
			  float m3, float m7, float m11, float m15);

	// Public Interface:

	void LoadIdentity(void);

	void LoadZero(void);

	void Transpose(void);

	void TransformPoint(const float in[4], float out[4]) const;
	void TransformPoint(const Vec3 & in, Vec3 & out) const;

	// Translation:
	void Translate(const Vec3 & trans);
	void TranslateX(float dist);
	void TranslateY(float dist);
	void TranslateZ(float dist);

	// Rotation:
	void Rotate(float angle, const Vec3 & axis); // Angle in radians!
	void RotateX(float angle);
	void RotateY(float angle);
	void RotateZ(float angle);

	// Scale:
	void Scale(const Vec3 & Scale);

	// Operators:
	Matrix4x4 operator + (const Matrix4x4 & other) const;
	Matrix4x4 operator - (const Matrix4x4 & other) const;
	Matrix4x4 operator * (const Matrix4x4 & other) const;

	// Multiply by scalar:
	Matrix4x4 operator * (float scalar) const;
};

#endif // __MATRIX4X4_HPP__